#include <memory.h>

#include "GInputDeviceMouse.h"


namespace GEngine
{
	/********************************************************/
	/*						GMouseState						*/
	/********************************************************/

	GMouseState::GMouseState()
	{
		Reset();
	}

	GMouseState::~GMouseState()
	{
	}

	void GMouseState::Reset()
	{
		DiffX = DiffY = DiffZ = 0;
		memset(SemanticStates, 0, sizeof(bool) * G_MS_COUNT);
	}

	const GMouseState&	GMouseState::operator = (const GMouseState& Other)
	{
		DiffX = Other.DiffX; DiffY = Other.DiffY; DiffZ = Other.DiffZ;	
		memcpy(SemanticStates, Other.SemanticStates, sizeof(bool) * G_MS_COUNT);

		return *this;
	}

	/********************************************************/
	/*					GInputDeviceMouse					*/
	/********************************************************/
	
	GInputDeviceMouse::GInputDeviceMouse(GModule* Owner, void* DeviceHandle)
		: GInputDevice(Owner, DeviceHandle)
	{
	}

	GInputDeviceMouse::~GInputDeviceMouse()
	{
	}

	void GInputDeviceMouse::AdvanceState()
	{
		// Copy to previous state
		PreviousState = CurrentState;

		// Clear current state's XYZ semantics.
		// These semantics should be reseted every frame
		// Since its not exactly a state machine
		CurrentState.SemanticStates[G_MS_PosX] = false;
		CurrentState.SemanticStates[G_MS_PosY] = false;
		CurrentState.SemanticStates[G_MS_PosZ] = false;
	}

	GMath::GVector3 GInputDeviceMouse::GetDifference() const
	{
		return GMath::GVector3(	(float)CurrentState.DiffX, 
								(float)CurrentState.DiffY, 
								(float)CurrentState.DiffZ);
	}

	bool GInputDeviceMouse::CheckInput(const GInput* Input) const OVERRIDE
	{
		GInputState State = Input->GetState();
		GMouseSemantics Semantic = Input->GetSemantic().Mouse;

		// Get the semantic current state
		bool Current = CurrentState.SemanticStates[Semantic];
		bool Previous = PreviousState.SemanticStates[Semantic];

		// Compare against previous state
		bool Result = false;
		switch (State)
		{
		case G_IS_PRESSED:
			Result = !Previous && Current;
			break;
		case G_IS_PRESSING:
			Result = Previous && Current;
			break;
		case G_IS_RELEASED:
			Result = Previous && !Current;
			break;
		}

		return Result;
	}

	GUInt32 GInputDeviceMouse::GetType() const OVERRIDE
	{
		return G_DT_MOUSE;
	}

	const char* GInputDeviceMouse::GetName() const OVERRIDE
	{
		return "Mouse";
	}

	void GInputDeviceMouse::Reset()
	{
		CurrentState.Reset();
		PreviousState.Reset();
	}

	bool GInputDeviceMouse::Update()
	{
		if (!GInputDevice::Update())
		{
			return false;
		}

		AdvanceState();

		return true;
	}

	const char* GInputDeviceMouse::GetSemanticName(GMouseSemantics Semantic)
	{
		return GMouseSemanticNames[Semantic];
	}
}